

import { Logger } from "../utils/Logger";
import { ProtoUtils } from "../socketserver/protocol/ProtoUtils";
import { ProtoConfig } from "../socketserver/protocol/ProtoConfig";
import { SocketMsg } from "../socketserver/socket/SocketMsg";
import SocketRequestData from "./SocketRequestData";
import { SocketClientReqManager } from "./SocketClientReqManager";
import { LogFileUtil } from "../utils/LogFileUtil";
import { WebSocketClientManager } from "./WebSocketClientManager";

const ws = require("ws");


export class WebSocketClient {

    private ws;
    private isConnecting: boolean;
    private isConnected: boolean;
    private requestMsgQue: Array<SocketRequestData> = [];

    private reqId: number = 1;
    public id: number;
    public url: string;

    private static count: number = 0
    private respCheckMap: Map<number, SocketRequestData> = new Map<number, SocketRequestData>();
    private isDestroy: boolean;
    public account: string;

    public init(url: string, id: number) {
        try {
            if (!this.isConnected && !this.isConnecting) {
                this.isConnecting = true
                this.url = url;
                this.id = id;
                this.ws = new ws(url);
                Logger.log("WebSocketClient===init=", url, this.id)
                this.ws.on('open', () => {
                    WebSocketClient.count++;
                    this.isConnecting = false;
                    Logger.info("ws onConnect===", this.url, this.id, WebSocketClient.count);
                    this.isConnected = true;
                    this.checkSendPack();
                });
                this.ws.on('message', (socketData) => {
                    this.onGameMsg(socketData)
                })
                this.ws.on("error", (err) => {
                    this.isConnected = false;
                    this.isConnecting = false;
                    Logger.error("WebSocketClient error=====", this.id, err)
                });
                this.ws.on('close', () => {
                    this.isConnected = false;
                    this.isConnecting = false;
                    Logger.info('disconnected', this.id, this.url);
                    this.destroy();
                });
            }
        } catch (error) {
            Logger.error("WebSocketClient error=", error)
        }
    }

    private onGameMsg(socketData) {
        try {
            let obj: object = JSON.parse(socketData)
            let id: number = obj["id"];
            let socketReqData: SocketRequestData | undefined = this.respCheckMap.get(id);
            if (socketReqData) {
                this.respCheckMap.delete(id)
                if (socketReqData.callback) {
                    socketReqData.callback(obj["data"])
                } else {
                    SocketClientReqManager.instance.onSocketMsg(obj["protoName"], obj["data"])
                }
            } else {
                SocketClientReqManager.instance.onSocketMsg(obj["protoName"], obj["data"])
            }

        } catch (error) {
            Logger.error("onGameMsg======error==", error);
        }
    }

    public async sendDataAsync(protoPack): Promise<any> {
        return new Promise((resolve, reject) => {
            this.sendData(protoPack, (data: object) => {
                resolve(data)
            })
        })
    }

    public sendData(protoPack, callback: Function) {
        let reqData: SocketRequestData = new SocketRequestData();
        reqData.id = this.reqId;
        this.reqId++;
        reqData.data = protoPack;
        reqData.callback = callback;
        this.requestMsgQue.push(reqData);
        if (this.isConnected) {
            this.checkSendPack();
        } else {
            this.init(this.url, this.id);
        }
    }

    public sendProto(protoPack, callback: Function = null) {
        let reqData: SocketRequestData = new SocketRequestData();
        reqData.id = this.reqId;
        this.reqId++;
        reqData.data = protoPack;
        reqData.callback = callback;
        this.requestMsgQue.push(reqData);
        if (this.isConnected) {
            this.checkSendPack();
        } else {
            this.init(this.url, this.id);
        }
    }

    private checkSendPack() {
        if (this.requestMsgQue.length > 0) {
            if (this.isConnected) {
                let socketData: SocketRequestData = this.requestMsgQue.shift();
                // let serialdata: Uint8Array = this.createSendPack(socketData);
                // let arrayBuffer: ArrayBuffer = serialdata.buffer;
                // this.respCheckMap.set(socketData.id, socketData);
                this.send(this.createSendPack(socketData));
                this.checkSendPack();
            }
        }
    }

    /**
 * 创建发送包
 * @param protoPack 
 */
    private createSendPack(socketData: SocketRequestData) {
        let data: object = {
            "id": socketData.id,
            "data": socketData.data
        }
        this.respCheckMap.set(socketData.id, socketData)
        return JSON.stringify(data)
    }

    // /**
    // * 创建发送包
    // * @param protoPack 
    // */
    // private createSendPack(socketData: SocketRequestData): Uint8Array {
    //     // let protoName: string = ProtoUtils.GetProtoName(socketData.data);
    //     // let protoType: number = ProtoConfig.getProtoRequestType(protoName);
    //     // let serialdata: Uint8Array = socketData.data.serializeBinary();
    //     // let totalPack = ProtoUtils.Create(ProtoConfig.PB_MESSAGE);
    //     // totalPack.setSeq(socketData.id);
    //     // totalPack.setHead(protoType);
    //     // totalPack.setData(serialdata);
    //     // Logger.log("createSendPack==", socketData);
    //     // return totalPack.serializeBinary();
    //     return
    // }

    private send(data) {
        if (this.isConnected) {
            this.ws.send(data);
        }
    }

    public close() {
        if (this.isConnected) {
            Logger.log("WebSocketClient.close")
            this.ws.close();
        }
    }

    public destroy() {
        if (!this.isDestroy) {
            this.isConnecting = false;
            this.isConnected = false
            this.isDestroy = true;
            WebSocketClientManager.instance.destoyWebSocketClient(this)
            this.account = null
            this.ws.removeAllListeners()
            this.ws = null;
            this.respCheckMap.clear();
            this.respCheckMap = null;
            this.requestMsgQue = null;
        }
    }
}